﻿using AutoMapper;
using HuiLian.Common.Output;
using HuiLian.Common;
using HuiLian.Model.Platform;
using HuiLian.Repository.Platform.Document;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HuiLian.Service.Platform.Document.Input;
using HuiLian.Service.Platform.Document.Output;
using HuiLian.Repository.Platform.DocumentImage;
using Microsoft.AspNetCore.Mvc;
using HuiLian.Common.Auth;
using HuiLian.Common.Input;
using HuiLian.Service.Platform.CallTime.Output;
using NPOI.POIFS.FileSystem;

namespace HuiLian.Service.Platform.Document
{
    public class DocumentService : IDocumentService
    {
        private readonly IMapper _mapper;
        private readonly IDocumentRepository _documentRepository;
        private readonly IDocumentImageRepository _documentImageRepository;

        public DocumentService(
            IMapper mapper,
            IDocumentRepository DocumentRepository,
            IDocumentImageRepository documentImageRepository
        )
        {
            _mapper = mapper;
            _documentRepository = DocumentRepository;
            _documentImageRepository = documentImageRepository;
        }

        public async Task<IResponseOutput> GetAsync(long id)
        {
            var result = await _documentRepository.GetAsync(id);

            return ResponseOutput.Ok(result);
        }

        public async Task<IResponseOutput> GetGroupAsync(long id)
        {
            var result = await _documentRepository.GetAsync<DocumentGetGroupOutput>(id);
            return ResponseOutput.Ok(result);
        }

        public async Task<IResponseOutput> GetMenuAsync(long id)
        {
            var result = await _documentRepository.GetAsync<DocumentGetMenuOutput>(id);
            return ResponseOutput.Ok(result);
        }

        public async Task<IResponseOutput> GetContentAsync(long id)
        {
            var result = await _documentRepository.GetAsync<DocumentGetContentOutput>(id);
            return ResponseOutput.Ok(result);
        }
        public async Task<IResponseOutput> GetHtmlAsync(long id)
        {
            var result = await _documentRepository.GetAsync<DocumentGetHtmlOutput>(id);
            return ResponseOutput.Ok(result);
        }
        public async Task<IResponseOutput> GetListAsync(string key, DateTime? start, DateTime? end)
        {
            if (end.HasValue)
            {
                end = end.Value.AddDays(1);
            }

            var data = await _documentRepository
                .WhereIf(key.NotNull(), a => a.Name.Contains(key) || a.Label.Contains(key))
                .WhereIf(start.HasValue && end.HasValue, a => a.CreatedTime.Value.BetweenEnd(start.Value, end.Value))
                .OrderBy(a => a.ParentId)
                .OrderBy(a => a.Sort)
                .ToListAsync<DocumentListOutput>();

            return ResponseOutput.Ok(data);
        }

        public async Task<IResponseOutput> GetListBySelfAsync(List<long> ids)
        {
            var data = await _documentRepository
                .WhereIf(ids != null && ids.Count > 0, a => ids.Contains(a.Id))
                .Where(a => a.Type == DocumentType.Group)
                .OrderBy(a => a.ParentId)
                .OrderBy(a => a.Sort)
                .ToListAsync<DocumentListOutput>();

            return ResponseOutput.Ok(data);
        }

        public async Task<IResponseOutput> GetImageListAsync(long id)
        {
            var result = await _documentImageRepository.Select
                .Where(a => a.DocumentId == id)
                .OrderByDescending(a => a.Id)
                .ToListAsync(a => a.Url);

            return ResponseOutput.Ok(result);
        }

        public async Task<IResponseOutput> AddGroupAsync(DocumentAddGroupInput input)
        {
            var entity = _mapper.Map<DocumentEntity>(input);
            var id = (await _documentRepository.InsertAsync(entity)).Id;

            return ResponseOutput.Result(id > 0);
        }

        public async Task<IResponseOutput> AddMenuAsync(DocumentAddMenuInput input)
        {
            var entity = _mapper.Map<DocumentEntity>(input);
            var id = (await _documentRepository.InsertAsync(entity)).Id;

            return ResponseOutput.Result(id > 0);
        }

        public async Task<IResponseOutput> AddImageAsync(DocumentAddImageInput input)
        {
            var entity = _mapper.Map<DocumentImageEntity>(input);
            var id = (await _documentImageRepository.InsertAsync(entity)).Id;

            return ResponseOutput.Result(id > 0);
        }

        public async Task<IResponseOutput> UpdateGroupAsync(DocumentUpdateGroupInput input)
        {
            var result = false;
            if (input != null && input.Id > 0)
            {
                var entity = await _documentRepository.GetAsync(input.Id);
                entity = _mapper.Map(input, entity);
                result = (await _documentRepository.UpdateAsync(entity)) > 0;
            }

            return ResponseOutput.Result(result);
        }

        public async Task<IResponseOutput> UpdateMenuAsync(DocumentUpdateMenuInput input)
        {
            var result = false;
            if (input != null && input.Id > 0)
            {
                var entity = await _documentRepository.GetAsync(input.Id);
                entity = _mapper.Map(input, entity);
                result = (await _documentRepository.UpdateAsync(entity)) > 0;
            }

            return ResponseOutput.Result(result);
        }

        public async Task<IResponseOutput> UpdateContentAsync(DocumentUpdateContentInput input)
        {
            var result = false;
            if (input != null && input.Id > 0)
            {
                var entity = await _documentRepository.GetAsync(input.Id);
                entity = _mapper.Map(input, entity);
                // 如果是连接，那么使用内容做为连接的地址
                if (entity.Type == DocumentType.URL)
                {
                    entity.Html = entity.Content;
                }
                result = (await _documentRepository.UpdateAsync(entity)) > 0;
            }

            return ResponseOutput.Result(result);
        }

        public async Task<IResponseOutput> DeleteAsync(long id)
        {
            var result = false;
            if (id > 0)
            {
                result = (await _documentRepository.DeleteAsync(m => m.Id == id)) > 0;
            }

            return ResponseOutput.Result(result);
        }

        public async Task<IResponseOutput> DeleteImageAsync(long documentId, string url)
        {
            var result = false;
            if (documentId > 0 && url.NotNull())
            {
                result = (await _documentImageRepository.DeleteAsync(m => m.DocumentId == documentId && m.Url == url)) > 0;
            }

            return ResponseOutput.Result(result);
        }

        public async Task<IResponseOutput> SoftDeleteAsync(long id)
        {
            var result = await _documentRepository.SoftDeleteAsync(id);
            return ResponseOutput.Result(result);
        }

        public async Task<IResponseOutput> GetPlainListAsync()
        {
            var documents = await _documentRepository.Select
                .OrderBy(a => a.ParentId)
                .OrderBy(a => a.Sort)
                .ToListAsync(a => new { a.Id, a.ParentId, a.Label, a.Type, a.Opened });

            var menus = documents
                .Where(a => (new[] { DocumentType.Group, DocumentType.Markdown }).Contains(a.Type))
                .Select(a => new
                {
                    a.Id,
                    a.ParentId,
                    a.Label,
                    a.Type,
                    a.Opened
                });

            return ResponseOutput.Ok(menus);
        }

        public async Task<IResponseOutput> GetPlainListAsync(long parentId)
        {
            var documents = await _documentRepository.Select.Where(w => w.ParentId == parentId)
                .OrderBy(a => a.Sort)
                .ToListAsync(a => new { a.Id, a.Label, a.Name, a.Description, a.Type });

            return ResponseOutput.Ok(documents);
        }
        public async Task<IResponseOutput> GetListByParentAsync(long parentId)
        {
            var documents = await _documentRepository.Select.Where(w => w.ParentId == parentId)
                .OrderBy(a => a.Sort)
                .ToListAsync(a => new { a.Id, a.Label, a.Name, a.Type, a.Html });

            var ids = documents.Select(c => c.Id).ToList();

            var images = await _documentImageRepository.Select
               .Where(a => ids.Contains(a.DocumentId))
               .OrderByDescending(a => a.Id)
               .ToListAsync(a => new { a.DocumentId, a.Url });

            return ResponseOutput.Ok(new { documents, images });
        }
        public async Task<string> GetChineseDistricts()
        {
            var documents = await _documentRepository.Select.Where(w => w.Type == DocumentType.Group)
                .OrderBy(a => a.Sort)
                .ToListAsync(a => new ChineseDistrictsOutput { Id = a.Id, ParentId = a.ParentId, Label = a.Label });

            return GetChineseDistricts(documents);
        }
        private string GetChineseDistricts(IList<ChineseDistrictsOutput> ds)
        {
            var province = new System.Text.StringBuilder();
            var city = new System.Text.StringBuilder();
            var river = new System.Text.StringBuilder();

            province.Append("86:{");
            foreach (var p in ds.Where(w => w.ParentId == 0))
            {
                province.Append(string.Format("{0}:'{1}'", p.Id, p.Label));
                city.Append(p.Id + ":{");
                foreach (var c in ds.Where(w => w.ParentId == p.Id))
                {
                    city.Append(string.Format("{0}:'{1}'", c.Id, c.Label));
                    river.Append(c.Id + ":{");
                    foreach (var r in ds.Where(w => w.ParentId == c.Id))
                    {
                        river.Append(string.Format("{0}:'{1}'", r.Id, r.Label));
                    }
                    river.Append("},");
                }
                city.Append("},");
            }
            province.Append("},");

            return "{" + province.ToString() + city.ToString() + river.ToString().TrimEnd(',') + "};";
        }

        public async Task<IResponseOutput> GetImageListByDocumentIdAsync(long documentId)
        {
            var result = await _documentImageRepository.Select
                .Where(a => a.DocumentId == documentId)
                .OrderByDescending(a => a.Id)
                .ToListAsync(a => new GetImageListByDocumentIdOutput { FileName = a.FileName, Url = a.Url });

            return ResponseOutput.Ok(result);
        }

        /// <summary>
        /// 新增文档
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<IResponseOutput> AddDocumentAsync(AddDocumentInput input)
        {
            var count = await _documentRepository.Select.Where(p=> p.Name == input.Name).CountAsync();
            if(count > 0)
            {
                return ResponseOutput.NotOk("文档名称不能重复");
            }

            var entity = _mapper.Map<DocumentEntity>(input);
            var id = (await _documentRepository.InsertAsync(entity)).Id;

            return ResponseOutput.Result(id > 0);
        }

        /// <summary>
        /// 修改文档
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<IResponseOutput> UpdateDocumentAsync(UpdateDocumentInput input)
        {
            var count = await _documentRepository.Select.Where(p => p.Name == input.Name && p.Id != input.Id).CountAsync();
            if (count > 0)
            {
                return ResponseOutput.NotOk("文档名称不能重复");
            }

            var result = false;
            if (input != null && input.Id > 0)
            {
                var entity = await _documentRepository.GetAsync(input.Id);
                entity = _mapper.Map(input, entity);
                result = (await _documentRepository.UpdateAsync(entity)) > 0;
            }

            return ResponseOutput.Result(result);
        }

        public async Task<IResponseOutput> SoftDeleteDocumentAsync(long id)
        {
            var result = await _documentRepository.SoftDeleteAsync(id);
            return ResponseOutput.Result(result);
        }

        /// <summary>
        /// 查询分页文档记录
        /// </summary>
        /// <param name="input">分页信息</param>
        /// <returns></returns>
        public async Task<IResponseOutput> PageAsync(PageInput<DocumentEntity> input)
        {
            var key = input.Filter?.Name;

            var list = await _documentRepository.Select
            .WhereDynamicFilter(input.DynamicFilter)
            .WhereIf(key.NotNull(), a => a.Name.Contains(key))
            .Count(out var total)
            .OrderByDescending(true, c => c.Id)
            .Page(input.CurrentPage, input.PageSize)
            .ToListAsync(p => new DocumentListOutput { });

            var data = new PageOutput<DocumentListOutput>()
            {
                List = list,
                Total = total
            };

            return ResponseOutput.Ok(data);
        }
    }
}
